package org.msb.code.thread;


import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
import java.util.concurrent.locks.*;

/**
 * @Package org.zcl.thread
 * @PROJECT_NAME: question
 * @DESCRIPTION:
 * @USER: zhuchenglin
 * @DATE: 2022/6/1 11:43
 */
public class TestBase {

    public static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("hello thread");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * sleep
     */
    static class testSleep {
        public static void main(String[] args) {
            new Thread(() -> {
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread().getName() + ":A" + i);
                    try {
                        TimeUnit.MILLISECONDS.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();

            new Thread(() -> {
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread().getName() + ":B" + i);
                    try {
                        TimeUnit.MILLISECONDS.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }

    /**
     * yield方法
     */
    static class testYield {
        public static void main(String[] args) {
            new Thread(() -> {
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread().getName() + ":A" + i);
                    if (i % 10 == 0) {
                        Thread.yield();
                    }
                }
            }).start();

            new Thread(() -> {
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread().getName() + ":B" + i);
                    if (i % 10 == 0) {
                        Thread.yield();
                    }
                }
            }).start();
        }
    }

    /**
     * join方法
     */
    static class testJoin {
        public static void main(String[] args) {
            Thread t1 = new Thread(() -> {
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread().getName() + ":A" + i);
                    try {
                        TimeUnit.MILLISECONDS.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });

            Thread t2 = new Thread(() -> {
                try {
                    t1.join();
                    System.out.println(Thread.currentThread().getName() + ":B");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            t1.start();
            t2.start();
        }
    }

    /**
     * 线程状态
     */
    static class testState {
        public static void main(String[] args) {
            MyThread t = new MyThread();
            System.out.println(t.getState());
            t.start();
            try {
                System.out.println(t.getState());
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(t.getState());
        }
    }

    /**
     * 无锁情况下线程不安全
     */
    static class TestNoLcok implements Runnable {
        private int count = 100;

        @Override
        public void run() {
            count--;
            System.out.println(Thread.currentThread().getName() + ":count=" + count);
        }

        public static void main(String[] args) {
            TestNoLcok t = new TestNoLcok();
            for (int i = 0; i < 100; i++) {
                new Thread(t, "THREAD" + i).start();
            }
        }
    }

    /**
     * synchronized锁保证多线程调用下线程安全
     */
    static class TestSynchronized implements Runnable {
        private int count = 100;

        @Override
        public synchronized void run() {
            count--;
            System.out.println(Thread.currentThread().getName() + ":count=" + count);
        }

        public static void main(String[] args) {
            TestSynchronized t = new TestSynchronized();
            for (int i = 0; i < 100; i++) {
                new Thread(t, "THREAD" + i).start();
            }
        }
    }

    /**
     * synchronized方法和普通方法可以同时调用
     */
    static class TestSynchronized2 {
        public synchronized void m1() {
            System.out.println(Thread.currentThread().getName() + ":m1 start...");
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":m1 end...");
        }

        public void m2() {
            System.out.println(Thread.currentThread().getName() + ":m2 start...");
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":m2 end...");
        }

        public static void main(String[] args) {
            TestSynchronized2 t = new TestSynchronized2();
            new Thread(t::m1, "t1").start();
            new Thread(t::m2, "t2").start();
        }
    }

    /**
     * 面试题：模拟银行账户
     * 对业务写方法加锁
     * 对业务读方法不加锁
     * 这样行不行？
     */
    static class Account {

        String name;
        double balance;

        public synchronized void set(String name, double balance) {
            this.name = name;
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.balance = balance;
        }

        public double getBalance(String name) {
            return this.balance;
        }

        public synchronized double getBalance2(String name) {
            System.out.println(name);
            return this.balance;
        }

        public static void main(String[] args) {
            Account account = new Account();
            new Thread(() -> account.set("z3", 100.0)).start();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(account.getBalance("z3"));
            System.out.println(account.getBalance2("加了锁z3"));
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(account.getBalance("z3"));
        }
    }

    /**
     * 可重入锁
     */
    static class TestSynchronized3 {
        synchronized void m1() {
            System.out.println(Thread.currentThread().getName() + ":m1 start...");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            m2();
            System.out.println(Thread.currentThread().getName() + ":m1 end...");
        }

        synchronized void m2() {
            System.out.println(Thread.currentThread().getName() + ":m2 start...");
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":m2 end...");
        }

        public static void main(String[] args) {
            TestSynchronized2 t = new TestSynchronized2();
            new Thread(t::m1, "t1").start();
        }
    }

    /**
     * synchronized一定是可重入锁
     */
    static class TestSynchronizedParent {
        public synchronized void m() {
            System.out.println(Thread.currentThread().getName() + ":m start...");
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":m end...");
        }

        public static void main(String[] args) {
            TestSynchronizedChild t = new TestSynchronizedChild();
            new Thread(t::m, "t1").start();
        }
    }

    static class TestSynchronizedChild extends TestSynchronizedParent {
        @Override
        public synchronized void m() {
            System.out.println(Thread.currentThread().getName() + ":child m start...");
            super.m();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":child m end...");
        }
    }

    /**
     * 程序异常、锁释放，异常处理要小心，否正被其他线程运行可能访问到异常产生的数据
     */
    static class TestSynchronizedException {
        int count = 0;

        synchronized void m() {
            System.out.println(Thread.currentThread().getName() + ":child m start...");
            while (true) {
                count++;
                System.out.println(Thread.currentThread().getName() + ":count=" + count);
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (count == 5) {
                    int i = 1 / 0;
                    System.out.println(i);
                }
            }
        }

        public static void main(String[] args) {
            TestSynchronizedException t = new TestSynchronizedException();
            Runnable r = t::m;
            new Thread(r, "t1").start();
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(r, "t2").start();
        }
    }

    /**
     * volatile可变的
     * 保证线程可见性、禁止指令重排序
     */
    static class TestVolatile {
        volatile boolean running = true;

        void m() {
            System.out.println("m start");
            while (running) {

            }
            System.out.println("m end");

        }

        public static void main(String[] args) {
            TestVolatile t = new TestVolatile();
            new Thread(t::m, "t1").start();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            t.running = false;
        }
    }

    /**
     * 单例（饿汉式：线程安全）
     */
    static class SingletonE {
        private static final SingletonE INSTANCE = new SingletonE();

        private SingletonE() {
        }

        private static SingletonE getInstance() {
            return INSTANCE;
        }

        public static void main(String[] args) {
            SingletonE s1 = SingletonE.getInstance();
            SingletonE s2 = SingletonE.getInstance();
            System.out.println(s1 == s2);
        }
    }

    /**
     * 单例（饱汉式:线程不安全）
     */
    static class SingletonB {
        private static SingletonB INSTANCE;

        private SingletonB() {
        }

        private static SingletonB getInstance() {
            if (INSTANCE == null) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                INSTANCE = new SingletonB();
            }
            return INSTANCE;
        }

        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                new Thread(() -> {
                    System.out.println(SingletonB.getInstance().hashCode());
                }).start();
            }
        }
    }

    /**
     * 单例（饱汉式:线程安全）
     * 但是这种方式并不推荐，因为效率相对较低，每个线程在执行getInstance的时候都要进行同步。而如果instance已经实例化了可以直接返回，（4）的方式效率更高。
     */
    static class SingletonBSafe {
        private static SingletonBSafe INSTANCE;

        private SingletonBSafe() {
        }

        private static synchronized SingletonBSafe getInstance() {
            if (INSTANCE == null) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                INSTANCE = new SingletonBSafe();
            }
            return INSTANCE;
        }

        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                new Thread(() -> {
                    System.out.println(SingletonBSafe.getInstance().hashCode());
                }).start();
            }
        }
    }

    /**
     * 单例（饱汉式:线程不安全）
     * A，B两个线程同时进入到if(instance==null)的代码块，A线程拿到锁进入synchronized代码块，对instance进行实例化，结束并释放锁，
     * B线程便拿到锁，依然会进入到synchronized代码块对instance进行实例化。那么这样就对instance进行了两次实例化。
     */
    static class SingletonBSynchronized {
        private static SingletonBSynchronized INSTANCE;

        private SingletonBSynchronized() {
        }

        private static SingletonBSynchronized getInstance() {
            if (INSTANCE == null) {
                synchronized (SingletonBSynchronized.class) {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    INSTANCE = new SingletonBSynchronized();
                }
            }
            return INSTANCE;
        }

        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                new Thread(() -> {
                    System.out.println(SingletonBSynchronized.getInstance().hashCode());
                }).start();
            }
        }
    }

    /**
     * 双重校验(饿汉式：线程安全）
     */
    static class SingletonBDCL {
        private static volatile SingletonBDCL INSTANCE;

        private SingletonBDCL() {
        }

        private static SingletonBDCL getInstance() {
            if (INSTANCE == null) {
                // 1->null；2->null等待，1初始化完释放锁，2尝试拿到锁进入方法如果不检查可能会重复初始化，双重检查就避免了这种情况
                synchronized (SingletonBDCL.class) {
                    if (INSTANCE == null) {
                        try {
                            TimeUnit.SECONDS.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        INSTANCE = new SingletonBDCL();
                    }
                }

            }
            return INSTANCE;
        }

        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                new Thread(() -> {
                    System.out.println(SingletonBDCL.getInstance().hashCode());
                }).start();
            }
        }
    }

    /**
     * 通过枚举的方式无视反射和序列化的攻击【线程安全】
     */
    static class SingletonEnum {

        private SingletonEnum() {
        }

        public static SingletonEnum getInstance() {
            return Container.HOLDER.instance;
        }

        private enum Container {
            HOLDER;
            private SingletonEnum instance;

            Container() {
                instance = new SingletonEnum();
            }
        }

        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                new Thread(() -> {
                    System.out.println(SingletonBDCL.getInstance().hashCode());
                }).start();
            }
        }
    }

    /**
     * volatile不保证原子性
     */
    static class TestVolatileNoAutomic {
        volatile int count = 0;

        void m() {
            for (int i = 0; i < 10000; i++) {
                count++;
            }
        }

        public static void main(String[] args) {
            TestVolatileNoAutomic t = new TestVolatileNoAutomic();
            List<Thread> threads = new ArrayList<>();
            for (int i = 0; i < 10; i++) {
                threads.add(new Thread(t::m, "thread-" + i));
            }
            threads.forEach(Thread::start); // 启动线程

            threads.forEach((o) -> {
                try {
                    o.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            // 等所有线程执行结束打印
            System.out.println(t.count);
        }
    }

    /**
     * 锁细化
     */
    static class TestFineCoarseLock {
        volatile int count = 0;

        synchronized void m1() {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count++;
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

        void m2() {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (this) {
                // 锁只放在这个调用上
                count++;
            }
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 锁对象改变(对象做锁，不让其改变，加final)
     */
    static class TestSynchronizedObject {
        /*final*/ Object o = new Object();

        void m() {
            synchronized (o) {
                while (true) {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName());
                }
            }
        }

        public static void main(String[] args) {
            TestSynchronizedObject t = new TestSynchronizedObject();
            new Thread(t::m, "t1").start();

            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            Thread t2 = new Thread(t::m, "t2");
            t.o = new Object(); // t1一直执行不释放锁，t2如果不新建对象，一直不执行
            t2.start();
        }
    }

    /**
     * AtomXXX类都是原子性的:CAS（unsafe方法调用,cpu指令级别操作,不能被其他线程打断的;比较与期望值是否相等,相等返回true,否正false）的思想,保证并发时的无锁并发的安全性
     */
    static class CasAtomicInteger {
        AtomicInteger count = new AtomicInteger(0);

        void m() {
            for (int i = 0; i < 10000; i++) {
                count.incrementAndGet();
            }
        }

        public static void main(String[] args) {
            CasAtomicInteger t = new CasAtomicInteger();
            List<Thread> threads = new ArrayList<>();
            for (int i = 0; i < 10; i++) {
                threads.add(new Thread(t::m, "thread-" + i));
            }

            threads.forEach((o) -> o.start());

            threads.forEach((o) -> {
                try {
                    o.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            System.out.println(t.count.get());
        }
    }

    /**
     * AtomicVSAyncVSLongAdder
     */
    static class AtomicVSAyncVSLongAdder {
        static long count2 = 0L;
        static AtomicLong count1 = new AtomicLong(0L);
        static LongAdder count3 = new LongAdder(); // 分段锁

        public static void main(String[] args) {
            Thread[] threads = new Thread[1000];
            for (int i = 0; i < threads.length; i++) {
                threads[i] = new Thread(() -> {
                    for (int k = 0; k < 10000; k++) {
                        count1.incrementAndGet();
                    }
                });
            }
            long start = System.currentTimeMillis();
            for (Thread thread : threads) {
                thread.start();
            }
            for (Thread thread : threads) {
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            long end = System.currentTimeMillis();
            System.out.println("Atomic:" + count1.get() + " time:" + (end - start));
            System.out.println("---------------------------------------------------");
            Object lock = new Object();
            for (int i = 0; i < threads.length; i++) {
                threads[i] = new Thread(() -> {
                    for (int k = 0; k < 10000; k++) {
                        synchronized (lock) {
                            count2++;
                        }
                    }
                });
            }
            start = System.currentTimeMillis();
            for (Thread thread : threads) {
                thread.start();
            }
            for (Thread thread : threads) {
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            end = System.currentTimeMillis();
            System.out.println("sync:" + count1.get() + " time:" + (end - start));
            System.out.println("---------------------------------------------------");
            for (int i = 0; i < threads.length; i++) {
                threads[i] = new Thread(() -> {
                    for (int k = 0; k < 10000; k++) {
                        count3.increment();
                    }
                });
            }
            start = System.currentTimeMillis();
            for (Thread thread : threads) {
                thread.start();
            }
            for (Thread thread : threads) {
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            end = System.currentTimeMillis();
            System.out.println("LongAddr:" + count1.get() + " time:" + (end - start));
        }
    }

    /**
     * 可重入锁
     */
    static class TestSyncReentrantLock {
        synchronized void m1() {
            for (int i = 0; i < 10; i++) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(i);
                if (i == 2) {
                    // synchronized方法里调synchronized方法,拿的是同一把锁
                    m3();
                }
            }
        }


        synchronized void m2() {
            System.out.println(":m2 ...");
        }

        synchronized void m3() {
            System.out.println(":m3 ...");
        }

        public static void main(String[] args) {
            TestSyncReentrantLock t = new TestSyncReentrantLock();
            new Thread(t::m1, "t1").start();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // m2得不到锁
            new Thread(t::m2).start();
        }
    }

    /**
     * wait/notify
     */
    static class TestSync {
        public static void main(String[] args) {
            Object o = new Object();
            List<Integer> list = new ArrayList<>();

            new Thread(() -> {
                while (true) {
                    synchronized (o) {
                        if (list.size() != 5) {
                            try {
                                o.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println("线程B收到通知，开始执行自己的业务...");
                    }
                }
            }).start();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(() -> {
                synchronized (o) {
                    for (int i = 0; i < 10; i++) {
                        list.add(i);
                        System.out.println("线程A添加元素，此时list的size为：" + list.size());
                        try {
                            TimeUnit.MILLISECONDS.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        if (list.size() == 5) {
                            // 不释放锁
                            o.notify();
                        }
                    }
                }
            }).start();
        }
    }


    /**
     * 可重入锁ReentrantLock
     */
    static class TestReentrantLock {
        ReentrantLock lock = new ReentrantLock();

        void m1() {
            try {
                lock.lock();
                for (int i = 0; i < 10; i++) {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(i);
                    if (i == 2) {
                        // 拿的是同一把锁
                        m3();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }


        void m2() {
            try {
                lock.lock();
                System.out.println("m2 ...");
            } finally {
                lock.unlock();
            }
        }

        void m3() {
            try {
                lock.lock();
                System.out.println("m3 ...");
            } finally {
                lock.unlock();
            }
        }

        public static void main(String[] args) {
            TestReentrantLock t = new TestReentrantLock();
            new Thread(t::m1, "t1").start();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // m2得不到锁
            new Thread(t::m2).start();
        }
    }

    /**
     * 可重入锁ReentrantLock,tryLock
     */
    static class TestReentrantLock2 {
        ReentrantLock lock = new ReentrantLock();

        void m1() {
            try {
                lock.lock();
                for (int i = 0; i < 10; i++) {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(i);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }


        void m2() {
            boolean locked = false;
            try {
                // 第二个线程可以尝试获取锁
                locked = lock.tryLock(5, TimeUnit.SECONDS);
                System.out.println("m2 ..." + locked);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                if (locked) {
                    lock.unlock();
                }
            }
        }

        public static void main(String[] args) {
            TestReentrantLock2 t = new TestReentrantLock2();
            new Thread(t::m1, "t1").start();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // m2得不到锁
            new Thread(t::m2).start();
        }
    }

    /**
     * 可重入锁ReentrantLock,lockInterruptibly
     */
    static class TestReentrantLock3 {


        public static void main(String[] args) {
            Lock lock = new ReentrantLock();

            Thread t1 = new Thread(() -> {
                try {
                    // t1一直睡
                    lock.lock();
                    System.out.println("t1 start");
                    TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
                    System.out.println("t1 end");
                } catch (InterruptedException e) {
                    System.out.println("interrupted!");
                } finally {
                    lock.unlock();
                }
            });
            t1.start();

            Thread t2 = new Thread(() -> {
                try {
                    // t2一直等t1的锁，lockInterruptibly可以打断停止线程2，直接向下执行
                    lock.lockInterruptibly();
                    System.out.println("t2 start");
                    TimeUnit.SECONDS.sleep(5);
                    System.out.println("t2 end");
                } catch (InterruptedException e) {
                    System.out.println("interrupted!");
                } finally {
                    lock.unlock();
                }
            });
            t2.start();
            t2.interrupt();
        }
    }

    /**
     * 可重入锁ReentrantLock,lockInterruptibly
     */
    static class TestReentrantLockFair {
        static Lock lock = new ReentrantLock(true); // 公平锁

        public void m2() {
            for (int i = 0; i < 100; i++) {
                lock.lock();
                try {
                    // 发现前面线程在执行，放到队列等待执行，间隙性执行
                    System.out.println(Thread.currentThread().getName() + "获得锁");
                } finally {
                    lock.unlock();
                }
            }
        }

        public static void main(String[] args) {
            for (int i = 0; i < 2; i++) {
                TestReentrantLockFair t = new TestReentrantLockFair();
                new Thread(t::m2).start();
            }
        }

    }

    /**
     * CountDownLatch
     */
    static class TestCountDownLatch {
        static void usingCountDownLatch() {
            Thread[] threads = new Thread[100];
            CountDownLatch latch = new CountDownLatch(threads.length);
            for (int i = 0; i < threads.length; i++) {
                threads[i] = new Thread(() -> {
                    int result = 0;
                    for (int j = 0; j < 10000; j++) {
                        result += j;
                    }
                    latch.countDown();
                });
            }
            for (Thread thread : threads) {
                thread.start();
            }

            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end latch");
        }

        static void usingJoin() {
            Thread[] threads = new Thread[100];
            for (int i = 0; i < threads.length; i++) {
                threads[i] = new Thread(() -> {
                    int result = 0;
                    for (int j = 0; j < 10000; j++) {
                        result += j;
                    }
                });
            }
            for (Thread thread : threads) {
                thread.start();
            }

            for (Thread thread : threads) {
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("end join");
        }

        public static void main(String[] args) {
            usingCountDownLatch();
            usingJoin();
        }
    }

    /**
     * CyclicBarrier,满20个线程开始执行
     */
    static class TestCyclicBarrier {
        public static void main(String[] args) {
            CyclicBarrier barrier = new CyclicBarrier(20, () -> System.out.println("满人，发车"));

            for (int i = 0; i < 99; i++) {
                new Thread(() -> {
                    try {
                        barrier.await(); // 满20个执行
                    } catch (InterruptedException | BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }).start();
            }
        }
    }

    /**
     * Phaser，boyAndGirl hug,需要等arrive，然后eat到leave，最后hug
     */
    static class TestPhaser {
        static Random r = new Random();
        static MarriagePhaser phaser = new MarriagePhaser();

        static void milliSleep(int milli) {
            try {
                TimeUnit.MILLISECONDS.sleep(milli);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public static void main(String[] args) {
            // 由7个人参加
            phaser.bulkRegister(7);
            for (int i = 0; i < 5; i++) {
                new Thread(new Person("p" + i)).start();
            }
            new Thread(new Person("boy")).start();
            new Thread(new Person("girl")).start();

        }

        static class Person implements Runnable {
            String name;

            public Person(String name) {
                this.name = name;
            }

            public void arrive() {
                milliSleep(r.nextInt(1000));
                System.out.printf("%s arrive！\n", name);
                phaser.arriveAndAwaitAdvance();
            }

            public void eat() {
                milliSleep(r.nextInt(1000));
                System.out.printf("%s eat！\n", name);
                phaser.arriveAndAwaitAdvance();
            }

            public void leave() {
                milliSleep(r.nextInt(1000));
                System.out.printf("%s leave！\n", name);
                phaser.arriveAndAwaitAdvance();
            }

            public void hug() {
                if (name.equals("boy") || name.equals("girl")) {
                    milliSleep(r.nextInt(1000));
                    System.out.printf("%s hug！\n", name);
                    phaser.arriveAndAwaitAdvance();
                } else {
                    phaser.arriveAndDeregister();
                }
            }

            @Override
            public void run() {
                arrive();
                eat();
                leave();
                hug();
            }
        }

        static class MarriagePhaser extends Phaser {
            @Override
            protected boolean onAdvance(int phase, int registeredParties) {
                switch (phase) {
                    case 0:
                        System.out.println("every arrive!" + registeredParties);
                        return false;
                    case 1:
                        System.out.println("every eat!" + registeredParties);
                        return false;
                    case 2:
                        System.out.println("every leave!" + registeredParties);
                        return false;
                    case 4:
                        System.out.println("boy and girl hug!" + registeredParties);
                        // 所有线程结束
                        return true;
                    default:
                        return true;
                }
            }
        }
    }

    /**
     * 读写锁
     */
    static class TestReadWriteLock {
        static Lock lock = new ReentrantLock();
        static int value;

        static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
        static Lock readLock = readWriteLock.readLock();
        static Lock writeLock = readWriteLock.writeLock();

        static void read(Lock lock) {
            try {
                lock.lock();
                TimeUnit.SECONDS.sleep(1);
                System.out.println("read over!");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        static void write(Lock lock, int v) {
            try {
                lock.lock();
                TimeUnit.SECONDS.sleep(1);
                value = v;
                System.out.println("write over!");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        public static void main(String[] args) {
           /* Runnable readR = () -> read(lock);

            Runnable writeR = () -> write(lock, new Random().nextInt());

            for (int i = 0; i < 18; i++) {
                new Thread(readR).start();
            }

            for (int i = 0; i < 2; i++) {
                new Thread(writeR).start();
            }*/

            Runnable rLockR = () -> read(readLock);

            Runnable wLockR = () -> write(writeLock, new Random().nextInt());

            for (int i = 0; i < 18; i++) {
                new Thread(rLockR).start();
            }

            for (int i = 0; i < 2; i++) {
                new Thread(wLockR).start();
            }
        }
    }

    /**
     * Semaphore 信号量
     */
    static class TestSemaPhore {
        public static void main(String[] args) {
            Semaphore s = new Semaphore(1);
//            Semaphore s = new Semaphore(1, true);
            Thread t1 = new Thread(() -> {
                try {
                    s.acquire();
                    System.out.println("T1 running...");
                    TimeUnit.MILLISECONDS.sleep(200);
                    System.out.println("T1 end...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    s.release();
                }
            });

            Thread t2 = new Thread(() -> {
                try {
                    s.acquire();
                    System.out.println("T2 running...");
                    TimeUnit.MILLISECONDS.sleep(200);
                    System.out.println("T2 end...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    s.release();
                }
            });

            t1.start();
            t2.start();
        }
    }

    /**
     * Exchanger 线程直接交换数据用
     */
    static class TestExchanger {
        static Exchanger<String> exchanger = new Exchanger<>();

        public static void main(String[] args) {
            new Thread(() -> {
                String s = "T1";
                try {
                    s = exchanger.exchange(s);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " " + s);
            }, "t1").start();

            new Thread(() -> {
                String s = "T2";
                try {
                    s = exchanger.exchange(s);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " " + s);
            }, "t2").start();

            new Thread(() -> {
                String s = "T3";
                try {
                    s = exchanger.exchange(s);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " " + s);
            }, "t3").start();

            new Thread(() -> {
                String s = "T4";
                try {
                    s = exchanger.exchange(s);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " " + s);
            }, "t4").start();
        }
    }

    static class TestLockSupport {
        public static void main(String[] args) {
            Thread t = new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    System.out.println(i);
                    if (i == 5) {
                        // 指定具体的线程停下
                        LockSupport.park();
                    }
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t.start();
            try {
                TimeUnit.SECONDS.sleep(8);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("after 8 seconds");
            // 可以在park前执行，后面不用停车
            LockSupport.unpark(t);
        }
    }
}
